﻿// first_ffmpeg.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <fstream>
#include "xencode.h"
using namespace std;

extern "C" { //指定函数是C语言函数，函数名不包含重载标注
//引用ffmpeg头文件
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
}



int main(int argc, char* argv[])
{
    string filename = "400_300_25_preset";

    //支持两种编码格式
    AVCodecID codec_id = AV_CODEC_ID_H264;
    //AVCodecID codec_id = AV_CODEC_ID_HEVC;
    if (argc > 1)
    {
        string codec = argv[1];
        if (codec == "h265" || codec == "hevc")
        {
            codec_id = AV_CODEC_ID_HEVC;
        }
    }

    if (codec_id == AV_CODEC_ID_H264)
    {
        filename += ".h264";
    }
    else if (codec_id == AV_CODEC_ID_HEVC)
    {
        filename += ".h265";
    }
    //------支持两种编码格式

    //写入文件
    ofstream ofs;
    ofs.open(filename, ios::binary);


    XEncode xencode;
    auto context = xencode.Create(codec_id);

    context->width = 400;
    context->height = 300;
    xencode.set_context(context);
    xencode.SetOpt("crf", 18); //压缩方式，恒定速率因子CRF

    xencode.Open();

    //计算写入文件帧数，此处不关心SPS PPS IDR
    int count = 0;

    auto frame = xencode.CreateFrame();
    //二十秒视频 500帧
    for (int i = 0; i < 500; i++)
    {
        //生成AVFrame数据
        //Y
        for (int y = 0; y < context->height; y++)
        {
            for (int x = 0; x < context->width; x++)
            {
                //设定Y的色彩，等号后面是瞎填的
                frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
            }
        }

        //UV
        for (int y = 0; y < context->height / 2; y++)
        {
            for (int x = 0; x < context->width / 2; x++)
            {
                //设定UV的色彩，等号后面是瞎填的
                frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
                frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
            }
        }

        frame->pts = i; //显示的时间
        auto pkt = xencode.Encode(frame);
        if (pkt)
        {
            count++;
            ofs.write((char*)pkt->data, pkt->size);
            av_packet_free(&pkt);
            
        }
    }

    auto pkt_vec = xencode.GetBufferAVPacket();
    for (auto pkt : pkt_vec)
    {
        count++;
        ofs.write((char*)pkt->data, pkt->size);
        av_packet_free(&pkt);
    }


    av_frame_free(&frame);
    ofs.close();
    //释放上下文
    xencode.set_context(nullptr);
    cout << "encode " << count << endl;

    return 0;
}




// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
